unit options;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, DateUtils, fileutil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  StdCtrls, Buttons, ExtCtrls, EditBtn, FileCtrl, BCListBox,
  BCPanel, BCButton, IniFiles;

type
  TFontInfo = record
    FontName: string;
    FontSize: integer;
  end;

type
  TDataStorage = record
    DataFile: string;
    BackupPath: string;
  end;

type

  { Tform_options }

  Tform_options = class(TForm)
    btn_restore: TBCButton;
    btn_backup: TBCButton;
    Bevel1: TBevel;
    btn_apply: TBitBtn;
    btn_cancel: TBitBtn;
    btn_ok: TBitBtn;
    edit_backup_path: TDirectoryEdit;
    lb_backup_files: TFileListBox;
    edit_data_file: TFileNameEdit;
    GroupBox1: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    lb_note_type: TBCListBox;
    BCPanel1: TBCPanel;
    BCPanel2: TBCPanel;
    cb_font_name: TComboBox;
    cb_font_size: TComboBox;
    memo_preview: TMemo;
    page_control_options: TPageControl;
    pn_bottom: TPanel;
    ts_font: TTabSheet;
    ts_data: TTabSheet;
    procedure btn_applyClick(Sender: TObject);
    procedure btn_backupClick(Sender: TObject);
    procedure btn_cancelClick(Sender: TObject);
    procedure btn_okClick(Sender: TObject);
    procedure btn_restoreClick(Sender: TObject);
    procedure CancelButtonClick(Sender: TObject);
    procedure cb_font_nameSelect(Sender: TObject);
    procedure cb_font_sizeSelect(Sender: TObject);
    procedure CloseButtonClick(Sender: TObject);
    procedure edit_backup_pathChange(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure lb_note_typeClick(Sender: TObject);
    procedure OKButtonClick(Sender: TObject);
  private
    function ReadNoteFontConfig(note_type: integer): TFontInfo;
    procedure WriteNoteFontConfig(note_type: integer; font_name: string;
      font_size: integer);

    function ReadDataStorageConfig(): TDataStorage;
    procedure WriteDataStorageConfig(data_file_name, backup_file_path: string);
  public

  end;

var
  form_options: Tform_options;

implementation

uses
  main;
  {$R *.lfm}

  { Tform_options }

procedure Tform_options.WriteNoteFontConfig(note_type: integer;
  font_name: string; font_size: integer);
var
  ini: TIniFile;
  note_type_array: array [0..3] of string = ('text', 'markdown', 'code', 'rich');
begin
  ini := TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'config.ini');
  try
    ini.WriteString('editor', Format('%s_font_name', [note_type_array[note_type]]),
      font_name);
    ini.WriteInteger('editor', Format('%s_font_size', [note_type_array[note_type]]),
      font_size);
  finally
    ini.Free;
  end;
end;

procedure Tform_options.WriteDataStorageConfig(data_file_name, backup_file_path: string);
var
  ini: TIniFile;
begin
  ini := TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'config.ini');
  try
    ini.WriteString('data_storage', 'data_file', data_file_name);
    ini.WriteString('data_storage', 'backup_path', backup_file_path);
  finally
    ini.Free;
  end;
end;

function Tform_options.ReadNoteFontConfig(note_type: integer): TFontInfo;
var
  ini: TIniFile;
  note_type_array: array [0..3] of string = ('text', 'markdown', 'code', 'rich');
  font_name: string;
  font_size: integer;
  font_info: TFontInfo;
begin
  ini := TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'config.ini');
  try
    font_name := ini.ReadString('editor', Format('%s_font_name',
      [note_type_array[note_type]]), '宋体');
    font_size := ini.ReadInteger('editor', Format('%s_font_size',
      [note_type_array[note_type]]), 9);
    font_info.FontName := font_name;
    font_info.FontSize := font_size;
  finally
    ini.Free;
  end;
  Result := font_info;
end;

function Tform_options.ReadDataStorageConfig(): TDataStorage;
var
  ini: TIniFile;
  data_storage: TDataStorage;
  app_path: string;
begin
  app_path := ExtractFilePath(ParamStr(0));
  ini := TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'config.ini');
  try
    data_storage.DataFile := ini.ReadString('data_storage', 'data_file',
      Format('%sdata\note.db', [app_path]));
    data_storage.BackupPath :=
      ini.ReadString('data_storage', 'backup_path', Format('%sdata\', [app_path]));
  finally
    ini.Free;
  end;
  Result := data_storage;
end;

procedure Tform_options.CancelButtonClick(Sender: TObject);
begin
  self.Close;
end;

procedure Tform_options.btn_applyClick(Sender: TObject);
var
  note_type: integer;
begin
  // 字体设置--------------------------------------------
  note_type := lb_note_type.ItemIndex;
  self.WriteNoteFontConfig(note_type, cb_font_name.Text, StrToInt(cb_font_size.Text));
  // 数据文件--------------------------------------------
  self.WriteDataStorageConfig(edit_data_file.FileName, edit_backup_path.Directory);
end;

procedure Tform_options.btn_backupClick(Sender: TObject);
var
  src_data_filename, dest_data_filename: string;
  backup_path: string;
begin
  src_data_filename := edit_data_file.FileName;
  backup_path := edit_backup_path.Directory;
  if not FileExists(src_data_filename) then
  begin
    MessageDlg('警告', Format('请确认文件(%s)是否存在?',
      [src_data_filename]), mtWarning, [mbOK], 0);
    exit;
  end;
  if not DirectoryExists(backup_path) then
  begin
    MessageDlg('警告', Format('请确认文件夹(%s)是否存在?',
      [backup_path]), mtWarning, [mbOK], 0);
    exit;
  end;

  //const DateTimeFormat = 'data_yymmdd_hhnnss.db';
  dest_data_filename := Format('%s\data-%s.db',
    [backup_path, FormatDateTime('yyyy-mm-dd-hh-nn-ss', Now)]);
  try
    form_main.sqlite3_connection.Connected := False;
    try
      if not CopyFile(src_data_filename, dest_data_filename,
        [cffOverwriteFile], True) then
      begin
        MessageDlg('错误', Format('数据文件(%s)备份失败！',
          [dest_data_filename]), mtError, [mbOK], 0);
      end
      else
      begin
        lb_backup_files.UpdateFileList;
        lb_backup_files.Refresh;
      end;
    except
      on E: EInOutError do
      begin
        MessageDlg('错误', Format('数据文件(%s)备份产生读写异常:%s',
          [dest_data_filename, E.Message]), mtError, [mbOK], 0);
      end;
      on E: Exception do
      begin
        MessageDlg('错误', Format('数据文件(%s)备份产生未知异常:%s',
          [dest_data_filename, E.Message]), mtError, [mbOK], 0);
      end;
    end;
  finally
    form_main.sqlite3_connection.Connected := True;
  end;
end;

procedure Tform_options.btn_cancelClick(Sender: TObject);
begin
  self.Close;
end;

procedure Tform_options.btn_okClick(Sender: TObject);
var
  note_type: integer;
begin
  note_type := lb_note_type.ItemIndex;
  self.WriteNoteFontConfig(note_type, cb_font_name.Text, StrToInt(cb_font_size.Text));
  self.Close;
end;

procedure Tform_options.btn_restoreClick(Sender: TObject);
var
  src_data_filename, dest_data_filename: string;
begin
  if lb_backup_files.ItemIndex < 0 then
  begin
    MessageDlg('警告', '请先选择要从哪个数据文件恢复。', mtWarning,
      [mbOK], 0);
    exit;
  end;
  dest_data_filename := edit_data_file.FileName;
  src_data_filename := lb_backup_files.FileName;
  if not FileExists(src_data_filename) then
  begin
    MessageDlg('警告', Format('请确认备份文件(%s)是否存在?',
      [src_data_filename]), mtWarning, [mbOK], 0);
    exit;
  end;

  try
    form_main.sqlite3_connection.Connected := False;
    try
      if not CopyFile(src_data_filename, dest_data_filename,
        [cffOverwriteFile], True) then
      begin
        MessageDlg('错误', Format('数据文件(%s)恢复失败！',
          [dest_data_filename]), mtError, [mbOK], 0);
      end
      else
      begin
        MessageDlg('成功', Format('数据文件(%s)恢复成功！',
          [dest_data_filename]), mtInformation, [mbOK], 0);
      end;
    except
      on E: EInOutError do
      begin
        MessageDlg('错误', Format('数据文件(%s)恢复产生读写异常:%s',
          [dest_data_filename, E.Message]), mtError, [mbOK], 0);
      end;
      on E: Exception do
      begin
        MessageDlg('错误', Format('数据文件(%s)恢复产生未知异常:%s',
          [dest_data_filename, E.Message]), mtError, [mbOK], 0);
      end;
    end;
  finally
    form_main.sqlite3_connection.Connected := True;
  end;
end;

procedure Tform_options.cb_font_nameSelect(Sender: TObject);
begin
  memo_preview.Font.Name := cb_font_name.Text;
end;

procedure Tform_options.cb_font_sizeSelect(Sender: TObject);
begin
  memo_preview.Font.Size := StrToInt(cb_font_size.Text);
end;

procedure Tform_options.CloseButtonClick(Sender: TObject);
var
  note_type: integer;
begin
  note_type := lb_note_type.ItemIndex;
  self.WriteNoteFontConfig(note_type, cb_font_name.Text, StrToInt(cb_font_size.Text));
end;

procedure Tform_options.edit_backup_pathChange(Sender: TObject);
begin
  lb_backup_files.Directory := edit_backup_path.Directory;
end;

procedure Tform_options.FormShow(Sender: TObject);
var
  i: integer;
  font_size_array: array [0..16] of
  integer = (8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 36, 48, 72);
  font_info: TFontInfo;
  data_storage: TDataStorage;
begin
  page_control_options.TabIndex := 0;
  // 字体设置-------------------------------------------------------
  // 初始化字体及字号列表
  for i := 0 to screen.Fonts.Count - 1 do
  begin
    cb_font_name.Items.Add(screen.Fonts[i]);
  end;
  cb_font_name.ItemIndex := 0;

  for i := Low(font_size_array) to High(font_size_array) do
  begin
    cb_font_size.Items.Add(IntToStr(font_size_array[i]));
  end;
  cb_font_size.ItemIndex := 0;

  // 默认选择文本文件
  lb_note_type.Selected[0] := True;
  font_info := self.ReadNoteFontConfig(0);
  cb_font_name.Text := font_info.FontName;
  cb_font_size.Text := IntToStr(font_info.FontSize);
  memo_preview.Font.Name := font_info.FontName;
  memo_preview.Font.Size := font_info.FontSize;

  // 数据文件-------------------------------------------------------
  data_storage := self.ReadDataStorageConfig();
  edit_data_file.FileName := data_storage.DataFile;
  edit_backup_path.Directory := data_storage.BackupPath;
end;

procedure Tform_options.lb_note_typeClick(Sender: TObject);
var
  font_info: TFontInfo;
  note_type: integer;
begin
  note_type := lb_note_type.ItemIndex;
  font_info := self.ReadNoteFontConfig(note_type);
  cb_font_name.Text := font_info.FontName;
  cb_font_size.Text := IntToStr(font_info.FontSize);
  memo_preview.Font.Name := font_info.FontName;
  memo_preview.Font.Size := font_info.FontSize;
end;

procedure Tform_options.OKButtonClick(Sender: TObject);
begin
  self.Close;
end;

end.
